package com.simple.puzzle;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Random;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class PuzzleGame extends Activity implements OnClickListener {

	private final int PICTURE_CAPTURE = 1;
	private final int PICTURE_SELECT = 2;
	private static final int SELECT_PICTURE_FROM_RESOURCE = 3;

	private final int DEFAULT_BLANK_IMAGE_ID_STAGE_ONE = 12;
	private final int DEFAULT_BLANK_IMAGE_ID_STAGE_TWO = 16;
	private final int DEFAULT_BLANK_IMAGE_ID_STAGE_THREE = 20;

	int blank_image_id = DEFAULT_BLANK_IMAGE_ID_STAGE_ONE;
	boolean isRunning = false;
	boolean isPausing = false;
	Bitmap picture;

	ImageView captureIView;
	ImageView choiseIView;
	ImageView pictureView;
	ImageView hightScore;
	ImageView about;
	TextView leverIView;
	Chronometer chrono;
	LinearLayout content;

	Button start;
	Button reset;

	long playTime = 0;
	long total_time = 0;
	int lever = 1;
	ScoreList scores;

	// stage one
	static final int stage_one[] = { R.id.image_1, R.id.image_2, R.id.image_3,
			R.id.image_4, R.id.image_5, R.id.image_6, R.id.image_7,
			R.id.image_8, R.id.image_9, R.id.image_10, R.id.image_11,
			R.id.image_12, R.id.image_13 };

	static final int nextIndexStageOne[][] = { { 12, 1, 3 }, { 0, 2, 4 },
			{ 1, 5 }, { 0, 4, 6 }, { 1, 3, 5, 7 }, { 2, 4, 8 }, { 3, 7, 9 },
			{ 4, 6, 8, 10 }, { 7, 5, 11 }, { 6, 10 }, { 7, 9, 11 }, { 8, 10 },
			{ 0 } };
	// stage two
	static final int stage_two[] = { R.id.image_1, R.id.image_2, R.id.image_3,
			R.id.image_4, R.id.image_5, R.id.image_6, R.id.image_7,
			R.id.image_8, R.id.image_9, R.id.image_10, R.id.image_11,
			R.id.image_12, R.id.image_13, R.id.image_14, R.id.image_15,
			R.id.image_16, R.id.image_17 };

	static final int nextIndexStageTwo[][] = { { 16, 1, 4 }, { 0, 2, 5 },
			{ 1, 3, 6 }, { 2, 7 }, { 0, 5, 8 }, { 1, 4, 6, 9 },
			{ 2, 5, 7, 10 }, { 3, 6, 11, }, { 4, 9, 12 }, { 5, 8, 10, 13 },
			{ 6, 9, 11, 14 }, { 7, 10, 15 }, { 8, 13 }, { 9, 12, 14 },
			{ 10, 13, 15 }, { 11, 14 }, { 0 } };
	// stage three
	static final int stage_three[] = { R.id.image_1, R.id.image_2,
			R.id.image_3, R.id.image_4, R.id.image_5, R.id.image_6,
			R.id.image_7, R.id.image_8, R.id.image_9, R.id.image_10,
			R.id.image_11, R.id.image_12, R.id.image_13, R.id.image_14,
			R.id.image_15, R.id.image_16, R.id.image_17, R.id.image_18,
			R.id.image_19, R.id.image_20, R.id.image_21 };

	static final int nextIndexStageThree[][] = { { 20, 1, 4 }, { 0, 2, 5 },
			{ 1, 3, 6 }, { 2, 7 }, { 0, 5, 8 }, { 1, 4, 6, 9 },
			{ 2, 5, 7, 10 }, { 3, 6, 11, }, { 4, 9, 12 }, { 5, 8, 10, 13 },
			{ 6, 9, 11, 14 }, { 7, 10, 15 }, { 8, 13, 16 }, { 9, 12, 14, 17 },
			{ 10, 13, 15, 18 }, { 11, 14, 19 }, { 12, 17 }, { 13, 16, 18 },
			{ 14, 17, 19 }, { 15, 18 }, { 0 } };

	public Bitmap initPicture[];

	PanelController panels[];
	int stage[];
	int nextIndex[][];

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);

		setContentView(R.layout.main);

		content = (LinearLayout) findViewById(R.id.game_content);
		Stage stage = new Stage(this, 1);
		content.addView(stage);

		captureIView = (ImageView) findViewById(R.id.capture);
		choiseIView = (ImageView) findViewById(R.id.choise_picture);
		pictureView = (ImageView) findViewById(R.id.picture);
		hightScore = (ImageView) findViewById(R.id.high_score);
		about = (ImageView) findViewById(R.id.about);
		leverIView = (TextView) findViewById(R.id.lever);

		chrono = (Chronometer) findViewById(R.id.chronometer);

		start = (Button) findViewById(R.id.start);
		reset = (Button) findViewById(R.id.reset);

		reset.setOnClickListener(this);
		start.setOnClickListener(this);
		captureIView.setOnClickListener(this);
		choiseIView.setOnClickListener(this);
		hightScore.setOnClickListener(this);
		about.setOnClickListener(this);

		// get default picture
		picture = BitmapFactory.decodeResource(getResources(),
				R.drawable.pic_one);

		//
		scores = new ScoreList();

		createPanelController();

	}

	/**
	 * create panel controller
	 */
	private void createPanelController() {
		// TODO Auto-generated method stub

		Log.i("Lever", String.valueOf(lever));
		// setLever
		leverIView.setText("Lever: " + String.valueOf(lever));

		Picture pic;
		if (lever == 1) {
			stage = stage_one;
			pic = new Picture(picture);
			initPicture = pic.getDevidedPortion();
			blank_image_id = DEFAULT_BLANK_IMAGE_ID_STAGE_ONE;
			nextIndex = nextIndexStageOne;
		} else if (lever == 2) {
			stage = stage_two;
			pic = new Picture(picture, 700, 800, 4, 4);
			initPicture = pic.getDevidedPortion();
			blank_image_id = DEFAULT_BLANK_IMAGE_ID_STAGE_TWO;
			nextIndex = nextIndexStageTwo;
		} else if (lever == 3) {
			stage = stage_three;
			pic = new Picture(picture, 520, 650, 4, 5);
			initPicture = pic.getDevidedPortion();
			blank_image_id = DEFAULT_BLANK_IMAGE_ID_STAGE_THREE;
			nextIndex = nextIndexStageThree;
		}

		panels = new PanelController[stage.length];

		Log.i("panels size", String.valueOf(stage.length));
		Log.i("panels size", String.valueOf(initPicture.length));

		pictureView = (ImageView) findViewById(R.id.picture);
		pictureView.setOnClickListener(this);
		pictureView.setImageBitmap(picture);

		// insert blank picture
		Bitmap blank = BitmapFactory.decodeResource(getResources(),
				R.drawable.blank_image);
		initPicture[blank_image_id] = blank;

		for (int i = 0; i < stage.length; i++) {
			Log.i("index", String.valueOf(i));

			ImageView b = (ImageView) findViewById(stage[i]);
			Log.i("index", b.toString());
			panels[i] = new PanelController(b, i, nextIndex[i]);
		}
	}

	private void nextLever() {
		if (lever < 3)
			lever++;
		// reload content
		content.removeAllViews();
		Stage stage = new Stage(this, lever);
		content.addView(stage);

		Log.i("set content: ", "ok");
		createPanelController();

	}

	private void setLever(int lv) {
		lever = lv;

		content.removeAllViews();
		Stage stage = new Stage(this, lever);
		content.addView(stage);

		Log.i("set content: ", "ok");
		createPanelController();
	}

	/**
	 * init game
	 */
	private void initialGame() {
		for (int i = 0; i < stage.length; i++) {
			panels[i].setImageId(i);
		}
	}

	public void initGame() {
		isRunning = false;
		start.setText("Start");
		stopChronometer();
		initialGame();
	}

	/**
	 * stop game
	 */
	public void resetGame() {
		isRunning = false;
		isPausing = false;
		playTime = 0;
		total_time = 0;

		start.setText("Start");
		stopChronometer();
		setLever(1);
		initialGame();
	}

	/**
	 * check game status
	 */
	private boolean isCompleted() {
		for (int i = 0; i < initPicture.length; i++) {
			if (i != panels[i].getImageId())
				return false;
		}
		return true;
	}

	/**
	 * shuffle
	 */
	private void shuffle() {
		int size = initPicture.length;
		for (int i = 1; i < size - 1; i++) {
			int swap = (int) (Math.random() * (size - 1));
			if (swap != 0)
				panels[i].swapImage(panels[swap]);
		}
	}

	/**
	 * shuffle 2
	 */
	private void shufflePic() {

		// next swap
		int blank = blank_image_id;
		Random rand = new Random();
		for (int i = 1; i < 50; i++) {
			int next[] = nextIndex[blank];
			int iswp = rand.nextInt(next.length);
			if (next[iswp] != blank_image_id) {
				panels[blank].swapImage(panels[next[iswp]]);
				blank = next[iswp];
			}
		}
		// back
		while (blank != blank_image_id) {
			int next[] = nextIndex[blank];
			panels[blank].swapImage(panels[next[0]]);
			blank = next[0];
		}

	}

	/**
	 * start counting time
	 */
	private void startChronometer() {
		chrono.setBase(SystemClock.elapsedRealtime());
		chrono.start();
	}

	/**
	 * stop counting time
	 */
	private long stopChronometer() {
		chrono.stop();
		return SystemClock.elapsedRealtime() - chrono.getBase();
	}

	/**
	 * resume
	 */
	private void resume() {
		chrono.setBase(SystemClock.elapsedRealtime() - playTime);
		chrono.start();
	}

	/**
	 * game completed
	 */
	private void complete() {
		playTime = stopChronometer();
		total_time += playTime;

		AlertDialog.Builder b = new AlertDialog.Builder(this);
		b.setTitle(R.string.complete_title);
		b.setMessage((playTime / 1000) + "sec");
		// b.setIcon(R.drawable.congratulations);

		ImageView imageView = new ImageView(this);
		imageView.setOnClickListener(this);
		imageView.setImageResource(R.drawable.congratulations);
		b.setView(imageView);

		b.setPositiveButton(R.string.complete_button,
				new DialogInterface.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						// TODO Auto-generated method stub
						if (lever == 3)
							infoDialog();
						else
							nextLever();
						dialog.dismiss();
					}
				});
		b.show();
	}

	/**
	 * input info dialog
	 */
	public void infoDialog() {
		AlertDialog.Builder alert = new AlertDialog.Builder(this);
		alert.setTitle("Your name");
		alert.setMessage("High score");

		final EditText input = new EditText(this);
		alert.setView(input);

		alert.setPositiveButton("ok", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				String value = input.getText().toString();
				Score s = new Score(value, String.valueOf(total_time / 1000));
				scores.add(s);
				scores.save();
				dialog.dismiss();
			}
		});

		alert.show();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		super.onActivityResult(requestCode, resultCode, data);

		/*
		 * take picture
		 */
		if (requestCode == PICTURE_CAPTURE && resultCode == Activity.RESULT_OK) {
			picture = (Bitmap) data.getExtras().get("data");
			pictureView.setImageBitmap(picture);

			createPanelController();
		}
		/**
		 * select picture in mediastore
		 */
		else if (requestCode == PICTURE_SELECT
				&& resultCode == Activity.RESULT_OK) {
			Uri uri = data.getData();
			String path = getRealPathFromURI(uri);
			try {
				FileInputStream infile = new FileInputStream(path);
				BufferedInputStream buf = new BufferedInputStream(infile);
				picture = BitmapFactory.decodeStream(buf);
				pictureView.setImageBitmap(picture);

				createPanelController();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else if (requestCode == SELECT_PICTURE_FROM_RESOURCE
				&& resultCode == Activity.RESULT_OK) {
			int id = data.getIntExtra("picture", 0);
			picture = BitmapFactory.decodeResource(getResources(), id);
			createPanelController();
		}
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		/**
		 * take a picture
		 */
		if (v == captureIView) {
			Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
			startActivityForResult(intent, PICTURE_CAPTURE);
		}
		/**
		 * choise picture in mediastore
		 */
		else if (v == choiseIView) {
			Intent intent = new Intent(Intent.ACTION_PICK,
					MediaStore.Images.Media.INTERNAL_CONTENT_URI);
			startActivityForResult(intent, PICTURE_SELECT);
		}
		/**
		 * click shuffle button
		 */
		else if (v == start) {
			if (!isRunning) {
				shufflePic();
				shufflePic();
				startChronometer();
				isRunning = true;
				start.setText("Pause");
			} else if (!isPausing) {
				playTime = stopChronometer();
				start.setText("Resume");
				isPausing = true;
			} else {
				resume();
				start.setText("Pause");
				isPausing = false;
			}
		} else if (v == reset) {
			resetGame();
		}
		/**
		 * high score
		 */
		else if (v == hightScore) {
			// scores.reloadData();
			Intent intent = new Intent(PuzzleGame.this, HighScore.class);
			startActivity(intent);
		}
		/**
		 * about
		 */
		else if (v == about) {
			Intent intent = new Intent(PuzzleGame.this, About.class);
			startActivity(intent);

		} else if (v == pictureView) {
			if (!isRunning) {
				Intent intent = new Intent(PuzzleGame.this, ChoicePicture.class);
				startActivityForResult(intent, SELECT_PICTURE_FROM_RESOURCE);
			}
		}
	}

	/**
	 * get real path from URI
	 * 
	 * @param contentUri
	 * @return
	 */
	public String getRealPathFromURI(Uri contentUri) {
		String[] proj = { MediaColumns.DATA };
		Cursor cursor = managedQuery(contentUri, proj, // Which columns to
				// return
				null, // WHERE clause; which rows to return (all rows)
				null, // WHERE clause selection arguments (none)
				null); // Order-by clause (ascending by name)
		int column_index = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
		cursor.moveToFirst();
		return cursor.getString(column_index);
	}

	/**
	 * 
	 * @author levannghia
	 * 
	 */
	class PanelController implements OnClickListener, OnTouchListener {

		ImageView view;
		int currentImage = 0;
		final int next[];

		public PanelController(ImageView ibutton, int iresid, final int inext[]) {
			view = ibutton;
			next = inext;

			setImageId(iresid);
			view.setOnClickListener(this);
			view.setOnTouchListener(this);
		}

		public int setImageId(int resid) {
			int old = currentImage;
			currentImage = resid;
			view.setImageBitmap(initPicture[resid]);
			return old;
		}

		public int getImageId() {
			return currentImage;
		}

		public boolean isBlank() {
			return currentImage == blank_image_id;
		}

		public void swapImage(PanelController other) {
			int previous = other.setImageId(currentImage);
			setImageId(previous);
		}

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			// if (isRunning) {
			// for (int i = 0; i < next.length; ++i) {
			// if (panels[next[i]].isBlank()) {
			// swapImage(panels[next[i]]);
			// break;
			// }
			// }
			// if (isCompleted()) {
			// complete();
			// stopGame();
			// }
			// }
		}

		@Override
		public boolean onTouch(View v, MotionEvent event) {
			// TODO Auto-generated method stub
			if (event.getAction() == MotionEvent.ACTION_MOVE) {
				if (isRunning && !isPausing) {
					for (int i = 0; i < next.length; ++i) {
						if (panels[next[i]].isBlank()) {
							swapImage(panels[next[i]]);
							break;
						}
					}
					if (isCompleted()) {
						complete();
						initGame();
					}
				}

			}
			// String action = "";
			// switch (event.getAction()) {
			// case MotionEvent.ACTION_DOWN:
			// action = "ACTION_DOWN";
			// break;
			// case MotionEvent.ACTION_UP:
			// action = "ACTION_UP";
			// break;
			// case MotionEvent.ACTION_MOVE:
			// action = "ACTION_MOVE";
			// break;
			// case MotionEvent.ACTION_CANCEL:
			// action = "ACTION_CANCEL";
			// break;
			// }
			// Log.i("TOUCH EVENT", action);
			return false;
		}

	}
}